package com.car.postoffice;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Vector;

import com.car.comm.Assert;
import com.car.comm.Logger;
import com.car.framework.IDataMapping;

public class PostOffice {	
	private HashMap<String, ITransferWorker> workers;
	private HashMap<CAddress, IMailHandler> handlers;
	private HashMap<TPostMark, CMail> records;
	
	protected ITransferWorker GetWorker(String scheme) throws UnSupportedScheme{
		ITransferWorker worker = workers.get(scheme);
		if(worker == null){
			throw new UnSupportedScheme(scheme);
		}
		return worker;
	}
	
	public PostOffice(){
		workers = new HashMap<String, ITransferWorker>();
		handlers = new HashMap<CAddress, IMailHandler>();
		records = new HashMap<TPostMark, CMail>();
	}
	
	public void RegisterTransaferWorker(final String scheme,
										ITransferWorker worker){
		workers.put(scheme, worker);
	}
	
	public void RegisterHandler(final CAddress addr,
								IMailHandler handler){
		// 地址一般由框架分配，出现重复，说明框架分配有问题
		Assert.TRUE(handlers.containsKey(addr) == false , "");
		handlers.put(addr, handler);
	}
	
	public void UnRegisterHandler(final CAddress addr){
		handlers.remove(addr);
	}
	
	public final TPostMark SendMail(final CMail mail,
							  final int level,
							  final IDataMapping mapping) throws SendException, UnSupportedScheme{
		String dstScheme = mail.getEnvelope().getDstAddr().getScheme();
		TPostMark mark = TPostMark.CreateId(dstScheme, mapping);
		GetWorker(dstScheme).HandleMail(mark, mail, level);
		
		// 留底，从而知道回信到达的地址
		records.put(mark, mail);
		return mark;
	}
	
	public void ReplyMail(TPostMark mark,
						  CMailResult result,
						  byte[] mailContent,
						  Serializable mailObj){
		Logger.LogDebug("================Reply Mail{PostMark=" + mark + "}===========");
		CMail mail = records.get(mark);
		if(mail == null){
			// 可能已经取消或者删除，保证异步回调的正确性
			Logger.LogRun("ReplyMail cannot found mail[" + mark + "]");
			return ;
		}
		IMailHandler handler = handlers.get(mail.getEnvelope().getSrcAddr());
		if(handler == null){
			// 可能已经消亡
			Logger.LogRun("ReplyMail cannot found handler " + mail.getEnvelope().getSrcAddr());
			records.remove(mark);
			return ;
		}
		CMailReply reply = new CMailReply();
		reply.setHeader(mail.getHeader());
		reply.setMailContent(mailContent);
		reply.setResult(result);
		reply.setMailObj(mailObj);
		if(handler.isAtHome()){
			handler.HandleReply(reply);
		}else{
			handler.PutMail(reply);
		}
		records.remove(mark);
	}
	
	public void NotifyMail(CAddress addr,
						   CMailReply reply){
		Logger.LogDebug("Nofify Mail " + addr + " reply= " + reply.getHeader() + reply.getResult() );
		IMailHandler handler = handlers.get(addr);
		if(handler == null){
			Logger.LogDebug("NotifyMail cannot found handler " + addr);
			return ;
		}
		if(handler.isAtHome()){
			handler.HandleReply(reply);
		}else{
			handler.PutMail(reply);
		}
	}
	
	/**
	 * 取消一个请求的投递
	 * @param mark
	 */
	public void CancelMail(final TPostMark mark){
		try {
			GetWorker(mark.getScheme()).Cancel(mark);
		} catch (UnSupportedScheme e) {
			// 说明很可能是个错误的PostMark，不管他
			Logger.LogErr("Cancel " + mark + " " + e.getMessage());
			return ;
		}
		records.remove(mark);
	}
	
	/**
	 *  取消一个协议下的所有请求的投递
	 * @param scheme
	 */
	public void CancelAll(final String scheme){
		try {
			GetWorker(scheme).CancelAll();
		} catch (UnSupportedScheme e) {
			Logger.LogErr("Cancel All[scheme=" + scheme + "] " + e.getMessage());
			return ;
		}
		
		Vector<TPostMark> rmLst = new Vector<TPostMark>();
		for(Entry<TPostMark, CMail> entry : records.entrySet()){
			if(entry.getKey().getScheme().equals(scheme)){
				rmLst.add(entry.getKey());
			}
		}
		
		for(TPostMark mark : rmLst){
			records.remove(mark);
		}
	}
	
	/**
	 *  取消所有请求的投递
	 */
	public void CancelAll(){
		for(Entry<String, ITransferWorker> entry : workers.entrySet()){
			entry.getValue().CancelAll();
		}
		records.clear();
	}
	
}
